package com.zhny.aiot.solar.pull.curtain.plugin;

import com.google.common.collect.ImmutableMap;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import com.zhny.aiot.plugin.zhnygateway.GatewayEngine;
import com.zhny.aiot.plugin.zhnygateway.device.ZhnyConfig;
import com.zhny.aiot.plugin.zhnygateway.device.ZhnyDevice;
import com.zhny.aiot.plugin.zhnygateway.model.GatewayResponseMessage;
import com.zhny.aiot.plugin.zhnygateway.model.NodeRequestMessage;
import com.zhny.aiot.solar.pull.curtain.plugin.model.PullCurtainStoreEntry;
import com.zhny.aiot.solar.pull.curtain.plugin.model.Vol_Current;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class SolarPullCurtainDevice extends ZhnyDevice<PullCurtainStoreEntry> {
    private static final Logger logger = LoggerFactory.getLogger(SolarPullCurtainDevice.class);
    private final Map<String, Integer> CommandOperations;
    public SolarPullCurtainDevice(GatewayEngine engine, IDeviceFactory<ZhnyConfig> factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super (engine, factory, centerFacilities, entity);
        CommandOperations =  new ImmutableMap.Builder<String, Integer>()
                .put("open", 0x31)
                .put("close", 0x32)
                .put("stop", 0x30)
                .put("query", 0x39)
                .put("queryVoltage", 0x3B).build();
    }

    @Override
    public void onDecoder(GatewayResponseMessage message) {
        logger.info (message.toString ());
        int type = message.getDeviceType ();
        if(type == 0x11){
            logger.info("---start decoder solar pull curtain message---");
            onMessage(message);
        }
    }

    private void onMessage(GatewayResponseMessage message) {
        MessageEntry resultMsg = MessageUtils.createMessageEntry (this.getId ());
        resultMsg.setType(MessageType.RESULT);
        PullCurtainStoreEntry storeEntry = new PullCurtainStoreEntry ();
        int operation = message.getDeviceOper ();
        logger.info ("--- solar pull curtain current operation {}---",operation);
        if(operation >= 0x30 && operation <= 0x32){
            if(message.getDataLength () == 7){
                resultMsg.setType (MessageType.ERROR);
                resultMsg.setData ("水利机械阀加入任务失败");
                logger.error ("[deviceNo:{},controllerNo:{}] 水利机械阀加入任务[{}]失败"
                        , getConfig ().getAddress (), getConfig ().getChannelNo (), operation);
                nofity (resultMsg);
                return;
            }else if(operation == 0x30) {
                int volValue = message.getDeviceData ().readUnsignedShort ();
                int status = message.getDeviceData ().readUnsignedShort ();
//                storeEntry.setVoltage (0.0);
                storeEntry.setPullCurtainStatus ("停止");
            }
            else if(operation == 0x31){
                int volValue = message.getDeviceData ().readUnsignedShort ();
                int status = message.getDeviceData ().readUnsignedShort ();
//                storeEntry.setVoltage (0.0);
                storeEntry.setPullCurtainStatus ("开");
            } else if(operation == 0x32){
                int volValue = message.getDeviceData ().readUnsignedShort ();
                int status = message.getDeviceData ().readUnsignedShort ();
//                storeEntry.setVoltage (0.0);
                storeEntry.setPullCurtainStatus ("关");
            }
        } else if(operation == 0x39) {
            int volValue = message.getDeviceData ().readUnsignedShort ();
            int status = message.getDeviceData ().readByte ();
            String isOpenStatus = status== 1?"开":status==0?"关":"停止";
            Boolean isSotateStatus = message.getDeviceData ().readByte () == 1?true:false;
//            storeEntry.setVoltage (0.0);
            storeEntry.setPullCurtainStatus (isOpenStatus);
        }else if(operation == 0x3B){
            Vol_Current result = GetVol(message.getDeviceData ());
            if(result == null)
                return;
            storeEntry.setVoltage (result.getVol ());
            storeEntry.setCurrent (result.getCurrent ());
        }
        resultMsg.setData (storeEntry);

        logger.info("solar pull curtain store[{}]",storeEntry.toString());
        save (storeEntry);
        saveReal (storeEntry);
        nofity (resultMsg);
    }

    private Vol_Current GetVol(ByteBuf dataBuf)
    {
        if(dataBuf.readableBytes () <= 0)
            return null;
//        logger.info ("solar pull curtain get vol hex:{}", ByteBufUtil.hexDump (dataBuf));
//        18 28 11 0E 3B 01 03 F5 08 01 03 04 00 00 13 B3 B6 B6 B8 8E 58
        int add = dataBuf.readByte ();
        int oper = dataBuf.readByte ();
        int modSize = dataBuf.readByte();
        byte[] modData = new byte[modSize];
        dataBuf.readBytes (modData);
        int crc = dataBuf.readUnsignedShort ();
        if (add == 1)
        {
            if (modSize == 4)
            {
                double current = createCurrent((((modData[0] & 0xff) << 8) | (modData[1] & 0xff)));

                double vol = (((modData[2] & 0xff) << 8) | (modData[3] & 0xff))/100.0;

                return new  Vol_Current(current,vol);
            }
        }
        return null;
    }

    private double createCurrent(int current){
        byte symbol = (byte)(current >> 15);
        if (symbol != 0)//负数
        {
            int temValue = (int)(current & 0x7fff);
            int tempReverstTempValue = (int)(~temValue);
            int ReverstTempValue = (int)(tempReverstTempValue & 0xff);
            int endTempValue = (int)(ReverstTempValue + 1);
            int endValue = -endTempValue;
            return endValue/100.0;
        }
        else
        {
            return current/100.0;
        }
    }

    @Override
    protected NodeRequestMessage onCommand(TaskEntity taskEntity) {
        if(StringUtils.isNullOrEmpty (taskEntity.getMethodName ()))
            return null;

        Map<String,Object> command =new HashMap<> ();
        command.put (taskEntity.getMethodName (),null);
        logger.info ("config address[{}]",Integer.parseInt (getConfig ().getAddress ()));
        return encode (command);
    }

    private NodeRequestMessage encode(Map<String, Object> commandMap) {
        for (String id : commandMap.keySet ()){
            if(CommandOperations.containsKey (id)) {
                Integer oper=CommandOperations.get (id);
                byte[] volCmdBuf = null;
                if(oper == 0x3B)volCmdBuf = getVolMsgCmd ();
                int size = volCmdBuf == null ? 0:volCmdBuf.length;
                int length=4 + size;
                return new NodeRequestMessage (getzhnyType ()+128, length, oper, Integer.parseInt (getConfig ().getAddress ()), volCmdBuf);
            }
        }
        return null;
    }

    public byte[] getVolMsgCmd(){
        return new byte[]{0x01,0x03,0x00,0x00,0x00,0x02,(byte)0xC4,0x0B};
    }

    @Override
    protected int getzhnyType() {
        return 17;
    }

    @Override
    protected void disposable() {

    }
}
